/*
 * Copyright (c) 2009, Russell Weir
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package scripting;

import Type;

/**
* A container for vm dates. Unlike haxe, the month field is 1 based.
*
* @author Russell Weir
**/
class DateObject
{
	/** Four digit year **/
	public var year : Int;
	/** Month of year, 1-12 **/
	public var month : Int;
	/** Day of month, 1-31 **/
	public var day : Int;
	/** Hour of day, 0-23 **/
	public var hour : Int;
	/** Minutes, 0-59 **/
	public var min : Int;
	/** Seconds, 0-59 **/
	public var sec : Int;

	/**
	* Creates a new DateObject which is initialized to 0000-01-01 00:00:00
	*/
	public function new() {
		year = 0;
		month = 1;
		day = 1;
		hour = 0;
		min = 0;
		sec = 0;
	}

	/**
	* Create a DateObject from a Haxe Date
	*
	* @param date Haxe date to convert
	* @return new DateObject
	**/
	public static function ofDate(date : Date) : DateObject
	{
		var vdo = new DateObject();
		vdo.year = date.getFullYear();
		vdo.month = date.getMonth() + 1; // 1-12
		vdo.day = date.getDate(); // 1-31
		vdo.hour = date.getHours(); // 0-23
		vdo.min = date.getMinutes(); // 0-59
		vdo.sec = date.getSeconds(); // 0-59
		return vdo;
	}

	/**
	* Returns this instance as a dynamic object, with the fields
	* year, month, day, hour, min, sec
	**/
	public function toObject() : Dynamic {
		return {
			year : year,
			month : month,
			day : day,
			hour : hour,
			min : min,
			sec : sec,
		}
	}

	/**
	* Converts a haxe Date to DateObject format, or a DateObject format to a
	* haxe date.
	*
	* @param d Date or DateObject
	* @return DateObject from Date, Date from DateObject, or null on error
	*/
	public static function convert(d:Dynamic) : Dynamic
	{
		var vdo : DateObject = null;
		if(Std.is(d, Date)) {
			return DateObject.ofDate(cast d);
		}
		else if( Std.is(d, DateObject)) {
			vdo = cast d;
			return new Date(vdo.year, vdo.month, vdo.day, vdo.hour, vdo.min, vdo.sec);
		}
		else if( Std.is(d, Dictionary)) {
			return new Date(
				d.get("year") == null ? 0 : cast d.get("year"),
				d.get("month") == null ? 0 : cast d.get("month") - 1,
				d.get("day") == null ? 1 : cast d.get("day"),
				d.get("hour") == null ? 0 : cast d.get("hour"),
				d.get("min") == null ? 0 : cast d.get("min"),
				d.get("sec") == null ? 0 : cast d.get("sec"));
		}
		else { // anon object
			vdo = new DateObject();

			var fields = ["year", "month", "day"];
			for ( f in fields ) {
				if(!Reflect.hasField(d,f)) {
					trace("missing field " + f);
					return null;
				}
				var vt = Type.typeof(Reflect.field(d,f));
				if(vt != TInt && vt != TFloat) {
					trace("Bad type");
					return null;
				}
				if( f == "month" )
					Reflect.setField(vdo, f, Std.parseInt(Reflect.field(d,f))-1 );
				else
					Reflect.setField(vdo, f, Std.parseInt(Reflect.field(d,f)));
			}

			fields = ["hour", "min", "sec"];
			for ( f in fields ) {
				if(!Reflect.hasField(d,f))
					continue;
				var vt = Type.typeof(Reflect.field(d,f));
				if(vt != TInt && vt != TFloat)
					continue;

				Reflect.setField(vdo, f, Std.parseInt(Reflect.field(d,f)));
			}
			return new Date(vdo.year, vdo.month, vdo.day, vdo.hour, vdo.min, vdo.sec);
		}
	}
}
